/**
 * 高级验证规则
 */
import { ValidationResult } from '../types';

/**
 * 密码强度验证规则选项接口
 * @property {string} [pattern] - 密码强度模式字符串，通过字符类型来定义密码要求：
 *  - 包含大写字母(A-Z)表示需要大写字母
 *  - 包含小写字母(a-z)表示需要小写字母
 *  - 包含数字(0-9)表示需要数字
 *  - 包含其他字符表示需要特殊字符
 */
export interface PasswordStrengthValidationOptions {
    /**
     * 密码强度模式字符串，通过字符类型来定义密码要求：
     * - 包含大写字母(A-Z)表示需要大写字母
     * - 包含小写字母(a-z)表示需要小写字母
     * - 包含数字(0-9)表示需要数字
     * - 包含其他字符表示需要特殊字符
     */
    pattern?: string;
}

/**
 * 自定义验证规则选项接口
 */
export interface CustomValidationOptions {
    /**
     * 自定义验证函数
     */
    custom: (value: any) => boolean | string;
}

/**
 * 白名单/黑名单验证规则选项接口
 */
export interface ListValidationOptions {
    /**
     * 列表类型，可选值：'whitelist'（白名单）、'blacklist'（黑名单）
     */
    type: 'whitelist' | 'blacklist';

    /**
     * 列表项数组
     */
    list: any[];

    /**
     * 是否使用严格比较（可选，默认为true）
     */
    isStrict?: boolean;
}

/**
 * 自定义验证规则
 * @param {any} value - 要验证的值
 * @param {(value: any) => boolean | string | undefined} customValidator - 自定义验证函数
 * @returns {ValidationResult} 验证结果
 * 
 * @example
 * // 直接调用
 * const customFunc = (val) => val > 10 || '值必须大于10';
 * const result = validateCustom(15, customFunc);
 * console.log(result); // { valid: true, message: undefined }
 * 
 * // 使用validateRule
 * const ruleResult = validateRule(5, { type: 'custom', options: customFunc });
 * console.log(ruleResult); // { valid: false, message: '值必须大于10' }
 */
export function validateCustom(value: any, customValidator: CustomValidationOptions): ValidationResult {
    const { custom } = customValidator;
    const result = custom(value);
    const isValid = result === true;
    let message: string | undefined;

    if (!isValid && typeof result === 'string') {
        message = result;
    } else if (!isValid) {
        message = '验证失败';
    }

    return {
        valid: isValid,
        message
    };
}

/**
 * 密码强度验证规则
 * 
 * @param {any} value - 要验证的值
 * @param {PasswordStrengthValidationOptions} [options] - 密码强度验证选项
 * @param {string} [options.pattern] - 密码强度模式字符串，通过字符类型来定义密码要求：
 *  - 包含大写字母(A-Z)表示需要大写字母
 *  - 包含小写字母(a-z)表示需要小写字母
 *  - 包含数字(0-9)表示需要数字
 *  - 包含其他字符表示需要特殊字符
 * @returns {ValidationResult} 验证结果
 * @example
 * // 验证需要大写、小写、数字和特殊字符的密码
 * const result1 = validatePasswordStrength('Abc123!@#', { pattern: 'Aa1!' });
 * console.log(result1); // { valid: true, message: undefined }
 * 
 * // 验证只需要大写和数字的密码
 * const result2 = validatePasswordStrength('ABC123', { pattern: 'A1' });
 * console.log(result2); // { valid: true, message: undefined }
 * 
 * // 使用validateRule
 * const ruleResult = validateRule('weak', { 
 *   type: 'passwordStrength', 
 *   options: { pattern: 'Aa1' } 
 * });
 * console.log(ruleResult); // { valid: false, message: '密码必须包含大写字母、小写字母、数字' }
 */
export function validatePasswordStrength(value: any, options: PasswordStrengthValidationOptions = {}): ValidationResult {
    if (value === undefined || value === null || value === '') {
        return {
            valid: false,
            message: '请输入密码'
        };
    }

    const password = String(value);
    const pattern = options.pattern || '';

    // 根据pattern字符串确定密码要求
    const requireUppercase = /[A-Z]/.test(pattern);
    const requireLowercase = /[a-z]/.test(pattern);
    const requireNumbers = /\d/.test(pattern);
    const requireSpecialChars = /[^A-Za-z\d]/.test(pattern);

    let isValid = true;
    const requirements: string[] = [];

    // 检查大写字母
    if (requireUppercase) {
        const hasUppercase = /[A-Z]/.test(password);
        if (!hasUppercase) {
            isValid = false;
            requirements.push('大写字母');
        }
    }

    // 检查小写字母
    if (requireLowercase) {
        const hasLowercase = /[a-z]/.test(password);
        if (!hasLowercase) {
            isValid = false;
            requirements.push('小写字母');
        }
    }

    // 检查数字
    if (requireNumbers) {
        const hasNumbers = /\d/.test(password);
        if (!hasNumbers) {
            isValid = false;
            requirements.push('数字');
        }
    }

    // 检查特殊字符
    if (requireSpecialChars) {
        const hasSpecialChars = /[^A-Za-z\d]/.test(password);
        if (!hasSpecialChars) {
            isValid = false;
            requirements.push('特殊字符');
        }
    }

    return {
        valid: isValid,
        message: isValid ? undefined : `密码必须包含${requirements.join('、')}`
    };
}

/**
 * 白名单/黑名单验证规则
 * @param {any} value - 要验证的值
 * @param {ListValidationOptions} options - 白名单/黑名单验证选项
 * @param {string} [options.type] - 验证类型，可选值：'whitelist'（白名单）、'blacklist'（黑名单）
 * @param {any[]} [options.list] - 验证列表
 * @param {boolean} [options.isStrict] - 是否使用严格比较（可选，默认为true）
 * @returns {ValidationResult} 验证结果
 * @example
 * // 白名单验证
 * const result1 = validateList('apple', {
 *   type: 'whitelist',
 *   list: ['apple', 'banana', 'orange']
 * });
 * console.log(result1); // { valid: true, message: undefined }
 * 
 * // 黑名单验证
 * const result2 = validateList('admin', {
 *   type: 'blacklist',
 *   list: ['admin', 'root', 'system']
 * });
 * console.log(result2); // { valid: false, message: '值不能在黑名单中' }
 * 
 * // 使用宽松比较
 * const result3 = validateList(123, {
 *   type: 'whitelist',
 *   list: ['123', '456', '789'],
 *   isStrict: false
 * });
 * console.log(result3); // { valid: true, message: undefined }
 * 
 * // 使用validateRule
 * const ruleResult = validateRule('grape', { 
 *   type: 'list', 
 *   options: { type: 'whitelist', list: ['apple', 'banana', 'orange'] } 
 * });
 * console.log(ruleResult); // { valid: false, message: '值必须在白名单中' }
 */
export function validateList(value: any, options: ListValidationOptions): ValidationResult {
    if (options.list === undefined || !Array.isArray(options.list)) {
        return {
            valid: false,
            message: '验证列表无效'
        };
    }

    let isInList = false;

    // 根据比较方法检查值是否在列表中
    if (options.isStrict === false) {
        // 宽松比较（转换为字符串后比较）
        const valueStr = String(value);
        isInList = options.list.some(item => String(item) === valueStr);
    } else {
        // 严格比较
        isInList = options.list.includes(value);
    }

    if (options.type === 'whitelist') {
        // 白名单：值必须在列表中
        return {
            valid: isInList,
            message: isInList ? undefined : '值必须在白名单中'
        };
    } else if (options.type === 'blacklist') {
        // 黑名单：值不能在列表中
        return {
            valid: !isInList,
            message: isInList ? '值不能在黑名单中' : undefined
        };
    } else {
        return {
            valid: false,
            message: '不支持的列表类型'
        };
    }
}